/**
 * @file
 * @author dousha
 * @date 2020/11/30.
 */

#include "crypto_core.h"
#include "../Peripherals/entropy.h"
#include "../Peripherals/flash.h"
#include "../Peripherals/eeprom.h"
#include <sm4.h>
#include <string.h>

static uint8_t buf[32] = {0};
const uint8_t magic[16] = {
		0xca, 0xfe, 0xba, 0xbe,
		0xba, 0xad, 0xf0, 0x0d,
		0xba, 0xad, 0xca, 0xfe,
		0xfe, 0xed, 0xf0, 0x0d,
};
static uint32_t *masterKey = 0;

void generate_salt(uint8_t *out) {
	for (uint8_t i = 0; i < SALT_LENGTH; i++) {
		out[i] = entropy_read();
	}
}

uint8_t verify_login(const uint32_t *key) {
	flash_read_magic((uint32_t *) buf);
	sm4_decrypt_ecb(buf, 16, key, buf + 16);
	for (uint8_t i = 0; i < 16; i++) {
		if (buf[16 + i] != magic[i]) {
			return 0;
		}
	}
	masterKey = (uint32_t *) key;
	return 1;
}

void create_credential(const uint32_t *key) {
	masterKey = (uint32_t *) key;
	// create login magic
	sm4_encrypt_ecb(magic, 16, key, buf);
	flash_write_magic((uint32_t *) buf);
	// generate iv
	for (uint8_t i = 0; i < 16; i++) {
		buf[i] = entropy_read();
	}
	eeprom_write_small_page(EEPROM_IV_ADDR, buf, 16);
}

void prepare_encrypt() {
	memset(buf, 0, 32);
	eeprom_read(EEPROM_IV_ADDR, buf, 16);
}

void prepare_decrypt() {
	memset(buf, 0, 32);
	eeprom_read(EEPROM_IV_ADDR, buf, 16);
}

void encrypt_block(const uint8_t block[16], uint8_t out[16]) {
	uint8_t byte;
	sm4_encrypt_block_ecb(buf, 16, masterKey, buf + 16);
	for (uint8_t i = 0; i < 16; i++) {
		byte = buf[16 + i] ^ block[i];
		out[i] = byte;
		buf[i] = byte;
	}
}

void decrypt_block(const uint8_t block[16], uint8_t out[16]) {
	sm4_encrypt_block_ecb(buf, 16, masterKey, buf + 16); // yes, encrypt
	for (uint8_t i = 0; i < 16; i++) {
		out[i] = buf[i + 16] ^ block[i];
		buf[i] = block[i];
	}
}
